package com.zxjbyte.yiyi.module.plugin.socket.handler;

import com.zxjbyte.yiyi.framework.common.constant.HeaderMsg;
import com.zxjbyte.yiyi.framework.common.domain.message.StreamMessage;
import com.zxjbyte.yiyi.framework.common.util.ServletXUtil;
import com.zxjbyte.yiyi.module.plugin.socket.manager.WebSocketSessionManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 链接协议
 * ws://127.0.0.1:41080/ws?userId=123
 * 如果项目配置了 context-path 则请求路径需要加context-path
 * 例如：
 *     ws://127.0.0.1:41080/yiyi-boot/ws?userId=123
 *
 * @Author zhangxingjia
 * @Date 2024/7/14 20:55
 * @Version: 1.0
 */
@Slf4j
public class YiyiWebSocketHandler extends TextWebSocketHandler {

    /**
     * 当 WebSocket 连接成功建立时调用
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String query = Objects.requireNonNull(session.getUri()).getQuery();
        Map<String, List<String>> params = ServletXUtil.queryStringToMap(query);
        if (params == null || !params.containsKey("userId")) {
            throw new IllegalArgumentException("User ID cannot be null"); // 抛出异常
        }

        // 缓存用户会话信息
        String userId = params.get("userId").get(0);
        WebSocketSessionManager.addSession(userId, session);
        log.info("WebSocketHandler >>> New session established: {}, userId: {}", session.getId(), userId);
    }

    /**
     * 当服务器收到客户端发送的文本消息时调用
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 空消息不处理
        if (message.getPayloadLength() == 0) {
            return;
        }
        String payload = message.getPayload();
        if(message.getPayloadLength() == 4 && "ping".equals(payload)) {
            // 兼容处理客户端发送心跳消息为ping时，回复消息pong
            session.sendMessage(new TextMessage("pong"));
        }else{
            session.sendMessage(new TextMessage(StreamMessage.of(HeaderMsg.SEND_MESSAGE, "收到消息啦！").toJsonString()));
        }
    }

    /**
     * 当 WebSocket 连接关闭时调用
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        WebSocketSessionManager.removeSession(session);
        log.info("WebSocketHandler >>> Session closed: {}, onlineUserNumber: {}", session.getId(), WebSocketSessionManager.getOnlineCount());
    }

    /**
     * 当 WebSocket 连接中发生传输错误时调用
     * @param session
     * @param exception
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("WebSocketHandler >>> Transport error: ", exception);
    }
}
